﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.UI;


namespace pdftron.PDF.Tools
{
    public struct SettingsColor
    {
        public byte R;
        public byte G;
        public byte B;
        public bool Use; // For when you select an empty color.

        public SettingsColor(byte r, byte g, byte b, bool use)
        {
            R = r;
            G = g;
            B = b;
            Use = use;
        }
    }

    internal static class Settings
    {
        internal static Windows.Storage.ApplicationDataContainer roamingSettings =
                Windows.Storage.ApplicationData.Current.RoamingSettings;
        internal static bool HasFontSize { get { return HasValue("FontSize"); } }
        internal static double FontSize
        {
            get { return (double)GetValue("FontSize"); }
            set { SetValue("FontSize", value); }
        }

        internal static bool HasTextStrokeColor { get { return HasColor("TextStrokeColor"); } }
        internal static SettingsColor TextStrokeColor
        {
            get { return GetColor("TextStrokeColor"); }
            set { SetColor("TextStrokeColor", value); }
        }

        internal static bool HasTextFillColor { get { return HasColor("TextFillColor"); } }
        internal static SettingsColor TextFillColor
        {
            get { return GetColor("TextFillColor"); }
            set { SetColor("TextFillColor", value); }
        }

        internal static bool HasMarkupOpacity { get { return HasValue("MarkupOpacity"); } }
        internal static double MarkupOpacity
        {
            get { return (double)GetValue("MarkupOpacity"); }
            set { SetValue("MarkupOpacity", value); }
        }

        internal static bool HasMarkupStrokeThickness { get { return HasValue("MarkupStrokeThickness"); } }
        internal static double MarkupStrokeThickness
        {
            get { return (double)GetValue("MarkupStrokeThickness"); }
            set { SetValue("MarkupStrokeThickness", value); }
        }

        internal static bool HasMarkupFillColor { get { return HasColor("MarkupFillColor"); } }
        internal static SettingsColor MarkupFillColor
        {
            get { return GetColor("MarkupFillColor"); }
            set { SetColor("MarkupFillColor", value); }
        }

        internal static bool HasMarkupStrokeColor { get { return HasColor("MarkupStrokeColor"); } }
        internal static SettingsColor MarkupStrokeColor
        {
            get { return GetColor("MarkupStrokeColor"); }
            set { SetColor("MarkupStrokeColor", value); }
        }

        // Text Markups
        internal static bool HasTextMarkupOpacity { get { return HasValue("TextMarkupOpacity"); } }
        internal static double TextMarkupOpacity
        {
            get { return (double)GetValue("TextMarkupOpacity"); }
            set { SetValue("TextMarkupOpacity", value); }
        }

        internal static bool HasTextMarkupThickness { get { return HasValue("TextMarkupThickness"); } }
        internal static double TextMarkupThickness
        {
            get { return (double)GetValue("TextMarkupThickness"); }
            set { SetValue("TextMarkupThickness", value); }
        }

        internal static bool HasTextMarkupColor { get { return HasColor("TextMarkupColor"); } }
        internal static SettingsColor TextMarkupColor
        {
            get { return GetColor("TextMarkupColor"); }
            set { SetColor("TextMarkupColor", value); }
        }

        // Highlights
        internal static bool HasHightlightOpacity { get { return HasValue("HightlightOpacity"); } }
        internal static double HightlightOpacity
        {
            get { return (double)GetValue("HightlightOpacity"); }
            set { SetValue("HightlightOpacity", value); }
        }

        internal static bool HasHighlightColor { get { return HasColor("HighlightColor"); } }
        internal static SettingsColor HighlightColor
        {
            get { return GetColor("HighlightColor"); }
            set { SetColor("HighlightColor", value); }
        }



        internal static void SetColor(string key, SettingsColor color)
        {
            roamingSettings.Values["PDFViewCtrlTools" + key + "U"] = color.Use;
            roamingSettings.Values["PDFViewCtrlTools" + key + "R"] = color.R;
            roamingSettings.Values["PDFViewCtrlTools" + key + "G"] = color.G;
            roamingSettings.Values["PDFViewCtrlTools" + key + "B"] = color.B;
        }

        internal static bool HasColor(string key)
        {
            // Enough to check the 'U' flag
            return roamingSettings.Values.ContainsKey("PDFViewCtrlTools" + key + "U");

        }

        internal static SettingsColor GetColor(string key)
        {
            SettingsColor sc = new SettingsColor();
            sc.Use = (bool)roamingSettings.Values["PDFViewCtrlTools" + key + "U"];
            sc.R = (byte)roamingSettings.Values["PDFViewCtrlTools" + key + "R"];
            sc.G = (byte)roamingSettings.Values["PDFViewCtrlTools" + key + "G"];
            sc.B = (byte)roamingSettings.Values["PDFViewCtrlTools" + key + "B"];
            return sc;
        }


        internal static void SetValue(string key, object val)
        {
            roamingSettings.Values["PDFViewCtrlTools" + key] = val;
        }

        internal static bool HasValue(string key)
        {
            return roamingSettings.Values.ContainsKey("PDFViewCtrlTools" + key);
        }


        internal static object GetValue(string key)
        {
            object val = roamingSettings.Values["PDFViewCtrlTools" + key];
            if (val is Windows.Storage.ApplicationDataCompositeValue)
            {
                Windows.Storage.ApplicationDataCompositeValue colors = (Windows.Storage.ApplicationDataCompositeValue)val;
                SettingsColor color;
                color.Use = (bool)colors["Use"];
                color.R = (byte)colors["R"];
                color.G = (byte)colors["G"];
                color.B = (byte)colors["B"];
                return color;
            }         
            return roamingSettings.Values["PDFViewCtrlTools" + key];
        }


        #region Settings with Custom Strings

        private static IList<Color> DEFAULT_PRESET_COLOR_OPTIONS = new List<Color>() { Colors.Red, Colors.Orange, Colors.Yellow, Colors.Green, Colors.Teal, Colors.Blue, 
            Colors.Pink, Colors.Purple, Colors.Black, Colors.White };

        private const string SHAPE_STRING = "Markup_Property";
        private const string INK_STRING = "Ink_Property";
        private const string TEXT_MARKUP_STRING = "Text_Markup_Property";
        private const string HIGHLIGHT_STRING = "highlight_Property";
        private const string TEXT_ANNOT_STRING = "Text_Annot_Property";

        internal static SettingsColor DEFAULT_SHAPE_COLOR = new SettingsColor(255, 0, 0, true);
        internal static SettingsColor DEFAULT_SHAPE_FILL = new SettingsColor(255, 0, 0, false);
        internal static SettingsColor DEFAULT_INK_COLOR = new SettingsColor(255, 0, 0, true);
        internal static SettingsColor DEFAULT_TEXT_COLOR = new SettingsColor(255, 0, 0, true);
        internal static SettingsColor DEFAULT_TEXT_BACKGROUND = new SettingsColor(255, 255, 255, false);
        internal static SettingsColor DEFAULT_TEXTMARKUP_COLOR = new SettingsColor(255, 0, 0, true);
        internal static SettingsColor DEFAULT_TEXTHIGHLIGHT_COLOR = new SettingsColor(255, 255, 0, true);

        internal static double DEFAULT_THICKNESS = 1;
        internal static double DEFAULT_OPACITY = 1;
        internal static double DEFAULT_FONT_SIZE = 12;

        public enum PropertyType
        {
            thickness,
            opacity,
            fontsize,
            color,
        }

        internal static T GetCustomValue<T>(string key, T _default)
        {
            if (HasValue(key))
            {
                object val = roamingSettings.Values["PDFViewCtrlTools" + key];
                try
                {
                    T retval = (T)val;
                    if (retval != null)
                    {
                        return retval;
                    }
                }
                catch (Exception e)
                {
                    string errorString = string.Format("An error receiving setting for key {0}", key);
                    System.Diagnostics.Debug.WriteLine(errorString);
                    pdftron.PDF.Tools.Utilities.AnalyticsHandlerBase.CURRENT.SendException(e, "Tools", errorString);
                }
            }
            return _default;
        }

        internal static void SetCustomValue<T>(string key, T value)
        {
            roamingSettings.Values["PDFViewCtrlTools" + key] = value;
        }

        internal static IList<Color> GetPresetColors(ToolType toolType, bool hasFill)
        {
            string key = GetPresetColorKeyFromToolType(toolType, hasFill);
            if (HasValue(key))
            {
                object colors = GetValue(key);
                string colorString = colors as string;
                if (colorString != null)
                {
                    return ParseColorString(colorString);
                }
            }

            return DEFAULT_PRESET_COLOR_OPTIONS;
        }

        internal static void SetPresetColors(ToolType toolType, bool hasFill, IList<Color> colors)
        {
            string key = GetPresetColorKeyFromToolType(toolType, hasFill);
            string value = CreateColorString(colors);
            SetValue(key, value);
        }

        internal static IList<Color> ParseColorString(string colorString)
        {
            try
            {
                List<Color> colors = new List<Color>();
                char[] separateColors = { ':' };
                char[] separateBytes = { ',' };
                string[] colorStrings = colorString.Split(separateColors);
                foreach (string color in colorStrings)
                {
                    string[] byteStrings = color.Split(separateBytes);
                    if (byteStrings.Length == 3)
                    {
                        colors.Add(Color.FromArgb(255, Byte.Parse(byteStrings[0]), Byte.Parse(byteStrings[1]), Byte.Parse(byteStrings[2])));
                    }
                }
                return colors;
            }
            catch (Exception e)
            {
                pdftron.PDF.Tools.Utilities.AnalyticsHandlerBase.CURRENT.SendException(e);
            }
            return DEFAULT_PRESET_COLOR_OPTIONS;
        }

        internal static string CreateColorString(IList<Color> colors)
        {
            string colorString = "";
            foreach (Color color in colors)
            {
                string col = string.Format("{0},{1},{2}", color.R, color.G, color.B);
                if (!string.IsNullOrEmpty(colorString))
                {
                    colorString += ":";
                }
                colorString += col;
            }
            return colorString;
        }

        #region Specific Properties

        internal static double GetThickness(ToolType toolType)
        {
            try
            {
                string key = GetKeyFromToolType(toolType, PropertyType.thickness);
                if (HasValue(key))
                {
                    object val = GetValue(key);
                    return (double)val;
                }
            }
            catch (Exception e)
            {
                Utilities.AnalyticsHandlerBase.CURRENT.SendException(e);
            }
            return DEFAULT_THICKNESS;
        }

        internal static void SetThickness(ToolType toolType, double thickness)
        {
            try
            {
                string key = GetKeyFromToolType(toolType, PropertyType.thickness);
                SetValue(key, thickness);
            }
            catch (Exception e)
            {
                Utilities.AnalyticsHandlerBase.CURRENT.SendException(e);
            }
        }

        internal static double GetOpacity(ToolType toolType)
        {
            try
            {
                string key = GetKeyFromToolType(toolType, PropertyType.opacity);
                if (HasValue(key))
                {
                    object val = GetValue(key);
                    return (double)val;
                }
            }
            catch (Exception e)
            {
                Utilities.AnalyticsHandlerBase.CURRENT.SendException(e);
            }
            return DEFAULT_OPACITY;
        }

        internal static void SetOpacity(ToolType toolType, double opacity)
        {
            try
            {
                string key = GetKeyFromToolType(toolType, PropertyType.opacity);
                SetValue(key, opacity);
            }
            catch (Exception e)
            {
                Utilities.AnalyticsHandlerBase.CURRENT.SendException(e);
            }
        }

        internal static double GetFontSize(ToolType toolType)
        {
            try
            {
                string key = GetKeyFromToolType(toolType, PropertyType.fontsize);
                if (HasValue(key))
                {
                    object val = GetValue(key);
                    return (double)val;
                }
            }
            catch (Exception e)
            {
                Utilities.AnalyticsHandlerBase.CURRENT.SendException(e);
            }
            return DEFAULT_FONT_SIZE;
        }

        internal static void SetFontSize(ToolType toolType, double fontSize)
        {
            try
            {
                string key = GetKeyFromToolType(toolType, PropertyType.fontsize);
                SetValue(key, fontSize);
            }
            catch (Exception e)
            {
                Utilities.AnalyticsHandlerBase.CURRENT.SendException(e);
            }
        }

        internal static SettingsColor GetShapeColor(ToolType toolType, bool isFill)
        {
            try
            {
                string key = GetKeyFromToolType(toolType, PropertyType.color, isFill);
                key += "Selected";
                if (HasValue(key))
                {
                    object colorObj = GetValue(key);
                    if (colorObj is SettingsColor)
                    {
                        SettingsColor color = (SettingsColor)colorObj;
                        return color;
                    }
                }
            }
            catch (Exception e)
            {
                Utilities.AnalyticsHandlerBase.CURRENT.SendException(e);
            }
            return GetDefaultColor(toolType, isFill);
        }

        internal static void SetShapeColor(ToolType toolType, bool isFill, SettingsColor color)
        {
            try
            {
                string key = GetKeyFromToolType(toolType, PropertyType.color, isFill);
                SetColor(key, color);
            }
            catch (Exception e)
            {
                Utilities.AnalyticsHandlerBase.CURRENT.SendException(e);
            }
        }

        internal static SettingsColor GetDefaultColor(ToolType toolType, bool isFill)
        {
            switch (toolType)
            {
                case ToolType.e_text_annot_create:
                    if (isFill)
                    {
                        return DEFAULT_TEXT_BACKGROUND;
                    }
                    else
                    {
                        return DEFAULT_TEXT_COLOR;
                    }
                case ToolType.e_text_squiggly:
                case ToolType.e_text_strikeout:
                case ToolType.e_text_underline:
                    return DEFAULT_TEXTMARKUP_COLOR;
                case ToolType.e_text_highlight:
                    return DEFAULT_TEXTHIGHLIGHT_COLOR;
                default:
                    if ((toolType == ToolType.e_rect_create || toolType == ToolType.e_oval_create) && isFill)
                    {
                        return DEFAULT_SHAPE_FILL;
                    }
                    break;
            }
            return DEFAULT_SHAPE_COLOR;
        }

        #endregion Specific Properties


        #region Utility Functions

        private static string GetKeyFromToolType(ToolType toolType, PropertyType property, bool hasFill = false)
        {
            string retString = "";
            switch (toolType)
            {
                case ToolType.e_text_annot_create:
                    retString = TEXT_ANNOT_STRING;
                    break;
                case ToolType.e_text_squiggly:
                case ToolType.e_text_strikeout:
                case ToolType.e_text_underline:
                    retString = TEXT_MARKUP_STRING;
                    break;
                case ToolType.e_text_highlight:
                    retString = HIGHLIGHT_STRING;
                    break;
                case ToolType.e_ink_create:
                    retString = INK_STRING;
                    break;
                default:
                    retString = TEXT_ANNOT_STRING;
                    break;
            }
            retString += property.ToString();
            if (hasFill)
            {
                retString += "fill";
            }
            return retString;
        }

        private static string GetPresetColorKeyFromToolType(ToolType toolType, bool hasFill)
        {
            return GetKeyFromToolType(toolType, PropertyType.color, hasFill) + "PresetColors";
        }

        #endregion Utility Functions


        #endregion Settings with Custom Strings

    }
}
